/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "zlang_in.h"

struct TempFunctionInParamObject
{
	struct ZlangObject				*func_in_param_obj ;
	struct list_head				tmp_func_in_param_obj_list_node ;
} ;

static void InitTempFunctionInParamObjectList( struct list_head *func_in_param_obj_cache_list )
{
	INIT_LIST_HEAD( func_in_param_obj_cache_list );

	return;
}

static int AppendTempFunctionInParamObjectToList( struct ZlangObject *func_in_param_obj , struct list_head *func_in_param_obj_cache_list )
{
	struct TempFunctionInParamObject	*tmp_func_in_param_obj = NULL ;

	tmp_func_in_param_obj = (struct TempFunctionInParamObject *)malloc( sizeof(struct TempFunctionInParamObject) ) ;
	if( tmp_func_in_param_obj == NULL )
		return -1;
	memset( tmp_func_in_param_obj , 0x00 , sizeof(struct TempFunctionInParamObject) );

	tmp_func_in_param_obj->func_in_param_obj = func_in_param_obj ;
	list_add_tail( & (tmp_func_in_param_obj->tmp_func_in_param_obj_list_node) , func_in_param_obj_cache_list );

	return 0;
}

static struct TempFunctionInParamObject *TravelTempFunctionInParamObjectListNode( struct list_head *tmp_func_in_param_obj_list , struct TempFunctionInParamObject *tmp_func_in_param_obj )
{
	if( tmp_func_in_param_obj == NULL )
		return list_first_entry_or_null( tmp_func_in_param_obj_list , struct TempFunctionInParamObject , tmp_func_in_param_obj_list_node );
	else
		return list_next_entry_or_null( tmp_func_in_param_obj , tmp_func_in_param_obj_list , struct TempFunctionInParamObject , tmp_func_in_param_obj_list_node );
}

static void FreeTempFunctionInParamObjectList( struct list_head *tmp_func_in_param_obj_list )
{
	struct TempFunctionInParamObject	*curr_tmp_func_in_param_obj = NULL ;
	struct TempFunctionInParamObject	*next_tmp_func_in_param_obj = NULL ;

	list_for_each_entry_safe( curr_tmp_func_in_param_obj , next_tmp_func_in_param_obj , tmp_func_in_param_obj_list , struct TempFunctionInParamObject , tmp_func_in_param_obj_list_node )
	{
		list_del( & (curr_tmp_func_in_param_obj->tmp_func_in_param_obj_list_node) );

		free( curr_tmp_func_in_param_obj );
	}

	return;
}

int InterpretExpression_InvokeFunction( struct ZlangRuntime *rt , enum TokenType member_of_token_type , struct ZlangInterpretStatementSegmentContext *interp_stat_seg_ctx , struct ZlangInterpretStatementContext *interp_stat_ctx , struct ZlangObject *master_obj , char *func_name , struct ZlangObject **result_obj )
{
	struct ZlangObject				*funcp_obj = NULL ;
	
	struct ZlangTokenDataUnitHeader			*token_info1 = NULL ;
	char						*token1 = NULL ;
	struct ZlangTokenDataUnitHeader			*token_info2 = NULL ;
	char						*token2 = NULL ;
	struct ZlangTokenDataUnitHeader			*token_info3 = NULL ;
	char						*token3 = NULL ;
	char						*agent_obj_name = NULL ;
	struct ZlangObject				*agent_obj = NULL ;
	
	struct ZlangInterpretStatementContext		in_params_stat_ctx ;
	struct ZlangInterpretStatementContext		in_params_interp_stat_ctx ;
	
	struct ZlangObjectsStackFrame			*old_local_objs_stack_frame = NULL ;
	int						old_local_objs_stack_frame_curridx ;
	struct ZlangObjectsStackFrame			*old_tmp_objs_stack_frame = NULL ;
	int						old_tmp_objs_stack_frame_curridx ;
	struct ZlangDefersStackFrame			*old_defers_stack_frame = NULL ;
	int						old_defers_stack_frame_curridx ;
	struct ZlangObjectsStackFrame			*new_local_objs_stack_frame = NULL ;
	int						new_local_objs_stack_frame_curridx ;
	struct ZlangObjectsStackFrame			*new_tmp_objs_stack_frame = NULL ;
	int						new_tmp_objs_stack_frame_curridx ;
	struct ZlangDefersStackFrame			*new_defers_stack_frame = NULL ;
	int						new_defers_stack_frame_curridx ;
	
	struct list_head				tmp_func_in_param_obj_list ;
	struct TempFunctionInParamObject		*tmp_func_in_param_obj = NULL ;
	char						full_function_name_buf[ 1024 ] = "" ;
	char						vargs_full_function_name_buf[ 1024 ] = "" ;
	char						*p = NULL ;
	int						remain_len ;
	int						len ;
	struct ZlangObject				*obj = NULL ;
	struct ZlangObject				*func_in_param_obj = NULL ;
	struct ZlangFunction				*func = NULL ;
	struct ZlangObject				*in = NULL ;
	int						in_param_index ;
	struct ZlangFunctionParameter			*func_param = NULL ;
	
	struct ZlangObject				*restore_in_obj = NULL ;
	struct ZlangFunction				*restore_in_func = NULL ;
	struct ZlangTokenDataPageHeader			*restore_token_datapage_header = NULL ;
	char						*restore_token_dataunit = NULL ;
	struct ZlangTokenDataUnitHeader			*restore_token_info = NULL ;
	char						*restore_token = NULL ;
	
	int						nret = 0 ;
	
	CHECK_ALART_STACK_DEPTH( rt->zlang_stack_bottom,&rt )
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretExpression_InvokeFunction begin , master_obj[%s] func_name[%s]" , GetObjectName(master_obj) , func_name )
	
	memset( full_function_name_buf , 0x00 , sizeof(full_function_name_buf) );
	memset( vargs_full_function_name_buf , 0x00 , sizeof(vargs_full_function_name_buf) );
	p = full_function_name_buf ;
	remain_len = sizeof(full_function_name_buf) - 1 ;
	
	// funcp_obj = QueryObjectByObjectName( rt , func_name ) ;
	funcp_obj = QueryObjectInLocalObjectsStack( rt , func_name , NULL ) ;
	if( master_obj == NULL && funcp_obj )
	{
		struct ZlangFunction		*func = NULL ;
		
		if( IsTypeOf( rt , funcp_obj , GetFunctionPtrObjectInRuntimeObjectsHeap(rt) ) )
		{
			struct ZlangObject	*obj = NULL ;
			
			if( master_obj )
			{
				SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect object[%s] before functionptr[%s]" , GetObjectName(master_obj) , func_name )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_SYNTAX;
			}
			
			nret = CallRuntimeFunction_functionptr_GetObjectPtr( rt , funcp_obj , & obj ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return nret;
			}
			if( obj )
				master_obj = obj ;
			
			nret = CallRuntimeFunction_functionptr_GetFunctionPtr( rt , funcp_obj , & func ) ;
			if( nret )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return nret;
			}
			
			if( func )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "funcp[%s] -> func_name[%s]" , func_name , func->func_name )
				func_name = func->func_name ;
			}
		}
	}
	
	TEST_RUNTIME_DEBUG( rt )
	{
		DebugStack( rt );
	}
	
	len = snprintf( p , remain_len , "%s(" , func_name ) ;
	if( len >= 0 )
	{
		p += len ;
		remain_len -= len ;
	}
	
	strcpy( vargs_full_function_name_buf , full_function_name_buf );
	
	InitTempFunctionInParamObjectList( & tmp_func_in_param_obj_list );
	for( ; ; )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "assemble full_function_name_buf[%s]" , full_function_name_buf )
		
		memset( & in_params_stat_ctx , 0x00 , sizeof(struct ZlangInterpretStatementContext) );
		
		if( func_in_param_obj )
		{
			len = snprintf( p , remain_len , "," ) ;
			if( len >= 0 )
			{
				p += len ;
				remain_len -= len ;
			}
		}
		
		PEEKTOKEN( rt , token_info1 , token1 )
		if( token_info1->token_type == TOKEN_TYPE_ATOMIC ) /* atomic */
		{
			NEXTTOKEN( rt )
			
			in_params_stat_ctx.has_atomic_decorated = TRUE ;
		}
			
		PEEKTOKEN( rt , token_info1 , token1 )
		if( token_info1->token_type == TOKEN_TYPE_COMPARE_LT ) /* < */
		{
			NEXTTOKEN( rt )
			
			TRAVELTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
			QueryCharsetAliasAndChangeTokenInfo( rt , token_info2 , & token2 );
			
			TRAVELTOKEN_AND_SAVEINFO( rt , token_info3 , token3 )
			if( token_info3->token_type != TOKEN_TYPE_COMPARE_GT ) /* > */
			{
				FreeTempFunctionInParamObjectList( & (tmp_func_in_param_obj_list) );
				SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '>' but '%s'" , token2 )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_SYNTAX;
			}
			
			agent_obj_name = token2 ;
		}
		else
		{
			agent_obj_name = NULL ;
		}
		
		TEST_RUNTIME_DEBUG( rt )
		{
			TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
			PRINT_TABS_AND_FORMAT( rt , "CALL InterpretExpression , last_token[%s][%s]" , _zlang_token_type_str , rt->travel_token )
		}
		memset( & in_params_interp_stat_ctx , 0x00 , sizeof(struct ZlangInterpretStatementContext) );
		in_params_interp_stat_ctx.token_of_expression_end1 = TOKEN_TYPE_PART_OF_STATEMENT ;
		in_params_interp_stat_ctx.token_of_expression_end2 = TOKEN_TYPE_END_OF_SUB_EXPRESSION ;
		func_in_param_obj = NULL ;
		nret = InterpretExpression( rt , interp_stat_seg_ctx , & in_params_interp_stat_ctx , & func_in_param_obj ) ;
		TEST_RUNTIME_DEBUG( rt )
		{
			TOKENTYPE_TO_STRING( rt->travel_token_info->token_type , _zlang_token_type_str )
			PRINT_TABS(rt) printf( "InterpretExpression return[%d] last_token[%s][%s] " , nret , _zlang_token_type_str , rt->travel_token ); DebugPrintObject(rt,func_in_param_obj); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE
		}
		if( nret != ZLANG_INFO_END_OF_EXPRESSION )
		{
			FreeTempFunctionInParamObjectList( & (tmp_func_in_param_obj_list) );
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret;
		}
		NEXTTOKEN( rt )
		
		if( func_in_param_obj )
		{
			if( agent_obj_name )
				len = snprintf( p , remain_len , "%s" , agent_obj_name ) ;
			else
				len = snprintf( p , remain_len , "%s" , GetCloneObjectName(func_in_param_obj) ) ;
			if( len >= 0 )
			{
				p += len ;
				remain_len -= len ;
			}
			
			if( agent_obj_name && STRCMP( agent_obj_name , != , ZLANG_OBJECT_object ) && GetObjectDirectFunctions(func_in_param_obj) == NULL && GetObjectPropertiesEntity(func_in_param_obj) == NULL )
			{
				agent_obj = QueryGlobalObjectByObjectName( rt , agent_obj_name ) ;
				if( agent_obj == NULL )
				{
					FreeTempFunctionInParamObjectList( & (tmp_func_in_param_obj_list) );
					SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED , "object '%s' not imported or declared" , agent_obj_name )
					TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
					return ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED;
				}
				
				nret = InitObject( rt , func_in_param_obj , GetObjectName(func_in_param_obj) , GetObjectDirectFunctions(agent_obj) , ZLANG_INITOPTIONS_NO_CREATE_DIRECTPROPERTY ) ;
				if( nret )
				{
					FreeTempFunctionInParamObjectList( & (tmp_func_in_param_obj_list) );
					TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InitObject in param failed[%d]" , nret )
					TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
					return nret;
				}
				else
				{
					TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InitObject in param ok" )
				}
			}
			
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "func_in_param_obj " ); DebugPrintObject( rt , func_in_param_obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			
			AppendTempFunctionInParamObjectToList( func_in_param_obj , & (tmp_func_in_param_obj_list) );
			
			if( in_params_stat_ctx.has_atomic_decorated == TRUE )
			{
				CopyAtomicLock( obj , func_in_param_obj );
			}
		}
		
		if( rt->travel_token_info->token_type == TOKEN_TYPE_END_OF_SUB_EXPRESSION )
		{
			break;
		}
	}
	
	TEST_CHECKING(rt)
	{
		if( master_obj && GetObjectFunctionsEntity(master_obj) == NULL )
		{
			FreeTempFunctionInParamObjectList( & (tmp_func_in_param_obj_list) );
			(*result_obj) = master_obj ;
			return 0;
		}
	}
	
	old_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
	old_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
	old_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
	old_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
	old_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
	old_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "backup local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_local_objs_stack_frame_curridx,old_local_objs_stack_frame->full_func_name , old_local_objs_stack_frame->stack_bottom,old_local_objs_stack_frame->stack_in_params_top,old_local_objs_stack_frame->stack_out_params_top,old_local_objs_stack_frame->stack_local_var_top )
	
	IncreaseStackFrame( rt , NULL ) ;
	new_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
	new_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
	new_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
	new_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
	new_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
	new_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
	
	for( tmp_func_in_param_obj = TravelTempFunctionInParamObjectListNode( & (tmp_func_in_param_obj_list) , NULL ) ; tmp_func_in_param_obj ; tmp_func_in_param_obj = TravelTempFunctionInParamObjectListNode( & (tmp_func_in_param_obj_list) , tmp_func_in_param_obj ) )
	{
		obj = ReferObjectInLocalStack( rt , GetObjectName(tmp_func_in_param_obj->func_in_param_obj) , tmp_func_in_param_obj->func_in_param_obj ) ;
		if( obj == NULL )
		{
			FreeTempFunctionInParamObjectList( & (tmp_func_in_param_obj_list) );
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "ReferObjectInLocalStack in param failed[%d]" , nret )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_ALLOC;
		}
		else
		{
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "ReferObjectInLocalStack in param ok , " ); DebugPrintObject( rt , obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
		}
	}
	FreeTempFunctionInParamObjectList( & (tmp_func_in_param_obj_list) );

	len = snprintf( p , remain_len , ")" ) ;
	if( len >= 0 )
	{
		p += len ;
		remain_len -= len ;
	}
	
	strcat( vargs_full_function_name_buf , "...)" );

	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "finish assembled full_function_name_buf[%s] vargs_full_function_name_buf[%s]" , full_function_name_buf , vargs_full_function_name_buf )
	
	new_local_objs_stack_frame->stack_in_params_top = new_local_objs_stack_frame->stack_local_var_top ;
	
	if( master_obj )
	{
		if( IsObjectPropertiesEntityNull( master_obj ) )
		{
			if( IsObjectPropertiesEntityNull(master_obj) && member_of_token_type == TOKEN_TYPE_MEMBER_OF_NOTNULL )
			{
				new_local_objs_stack_frame->stack_out_params_top = new_local_objs_stack_frame->stack_local_var_top ;
				SetObjectsStackFullFuncName( new_local_objs_stack_frame , NULL );
				SetObjectsStackFullFuncName( new_tmp_objs_stack_frame , NULL );
				SetDefersStackFullFuncName( new_defers_stack_frame , NULL );
				DecreaseStackFrame( rt );
				TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "IsObjectPropertiesEntityNull(master_obj)[%d] && TOKEN_TYPE_MEMBER_OF_NOTNULL , " , IsObjectPropertiesEntityNull(master_obj) ); DebugPrintObject(rt,master_obj); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
				(*result_obj) = master_obj ;
				UnreferObject( rt , (*result_obj) );
				TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "directly return null_obj , " ); DebugPrintObject(rt,(*result_obj)); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
				TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
				return 0;
			}
			else if( GetObjectFunctionsEntity( master_obj ) )
			{
				nret = CreateObjectDirectProperty( rt , master_obj ) ;
				if( nret )
				{
					TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CreateObjectDirectProperty failed[%d]" , nret )
					TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
					return nret;
				}
			}
			else
			{
				SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_NO_FUNCTIONS_ENTITY , "no functions entity in object '%s' before call function[%s]" , GetObjectName(master_obj) , full_function_name_buf )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_NO_FUNCTIONS_ENTITY;
			}
		}
		
		func = QueryFunctionInObjectByFullFunctionName( rt , master_obj , full_function_name_buf ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryFunctionByFullFunctionNameInObject full_func_name[%s] in obj[%s] return func[%p]" , full_function_name_buf , GetObjectName(master_obj) , func ); }
		if( func == NULL )
		{
			func = QueryFunctionInObjectByFullFunctionName( rt , master_obj , vargs_full_function_name_buf ) ;
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryFunctionByFullFunctionNameInObject full_func_name[%s] in obj[%s] return func[%p]" , vargs_full_function_name_buf , GetObjectName(master_obj) , func ); }
		}
		if( func )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "master_obj[%p] rt->in_obj[%p] func->access_qualifier[%d] OBJECTACCESSQUALIFIER_PUBLIC[%d]" , master_obj , rt->in_obj , func->access_qualifier , OBJECTACCESSQUALIFIER_PUBLIC )
			if( master_obj == rt->in_obj || func->access_qualifier == OBJECTACCESSQUALIFIER_PUBLIC )
			{
				;
			}
			else
			{
				SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNCTION_IS_NOT_PUBLIC , "func '%s' or '%s' is not public in object '%s'" , full_function_name_buf , vargs_full_function_name_buf , GetObjectName(master_obj) )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_FUNCTION_IS_NOT_PUBLIC;
			}
		}
	}
	else if( rt->in_obj )
	{
		func = QueryFunctionInObjectByFullFunctionName( rt , rt->in_obj , full_function_name_buf ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryFunctionByFullFunctionNameInObject full_func_name[%s] in obj[%s] return func[%p]" , full_function_name_buf , GetObjectName(rt->in_obj) , func ); }
		if( func == NULL )
			func = QueryFunctionInObjectByFullFunctionName( rt , master_obj , vargs_full_function_name_buf ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryFunctionByFullFunctionNameInObject full_func_name[%s] in obj[%s] return func[%p]" , vargs_full_function_name_buf , GetObjectName(master_obj) , func ); }
		if( func == NULL )
			func = QueryGlobalFunctionByFullFunctionName( rt , full_function_name_buf ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryGlobalFunctionByFullFunctionName full_func_name[%s] return func[%p]" , full_function_name_buf , func ); }
		if( func == NULL )
			func = QueryGlobalFunctionByFullFunctionName( rt , vargs_full_function_name_buf ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryGlobalFunctionByFullFunctionName full_func_name[%s] return func[%p]" , vargs_full_function_name_buf , func ); }
	}
	else
	{
		func = QueryGlobalFunctionByFullFunctionName( rt , full_function_name_buf ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryGlobalFunctionByFullFunctionName full_func_name[%s] return func[%p]" , full_function_name_buf , func ); }
		if( func == NULL )
			func = QueryGlobalFunctionByFullFunctionName( rt , vargs_full_function_name_buf ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS_AND_FORMAT( rt , "QueryGlobalFunctionByFullFunctionName full_func_name[%s] return func[%p]" , vargs_full_function_name_buf , func ); }
	}
	if( func == NULL )
	{
		TEST_CHECKING(rt)
		{
			DecreaseStackFrame( rt );
			(*result_obj) = CloneObjectInTmpStack( rt , NULL , NULL ) ;
			if( (*result_obj) == NULL )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CloneObjectInTmpStack failed" )
				return GetRuntimeErrorNo(rt);
			}
			TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
			return 0;
		}
		
		if( master_obj )
		{
			TEST_RUNTIME_DEBUG( rt )
			{
				PRINT_TABS(rt) printf( "master_obj " ); DebugPrintObject( rt , master_obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE
				DebugPrintObjectFunctions( rt , master_obj );
			}
			
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_NOT_FOUND_IN_OBJECT , "function '%s' not found in object '%s'" , full_function_name_buf , GetObjectName(master_obj) )
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "obj[%s] functions :" , GetObjectName(master_obj) ); DebugPrintObjectFunctions( rt , master_obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_FUNC_NOT_FOUND_IN_OBJECT;
		}
		else if( rt->in_obj )
		{
			TEST_RUNTIME_DEBUG( rt )
			{
				PRINT_TABS(rt) printf( "rt->in_obj " ); DebugPrintObject( rt , rt->in_obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE
				DebugPrintObjectFunctions( rt , rt->in_obj );
			}
			
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_NOT_FOUND_IN_OBJECT , "function '%s' not found in object '%s'" , full_function_name_buf , GetObjectName(rt->in_obj) )
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "obj[%s] functions :" , GetObjectName(rt->in_obj) ); DebugPrintObjectFunctions( rt , rt->in_obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_FUNC_NOT_FOUND_IN_OBJECT;
		}
		else
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_FUNC_NOT_FOUND , "function '%s' not found" , full_function_name_buf )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_FUNC_NOT_FOUND;
		}
	}
	if( master_obj == NULL && rt->in_obj )
		master_obj = rt->in_obj ;
	
	if( func->out_param )
	{
		if( STRCMP( func->out_param->parent_obj_name , == , ZLANG_OBJECT_void ) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "out param 'void'" )
		}
		else if( STRCMP( func->out_param->parent_obj_name , == , ZLANG_OBJECT_object ) )
		{
			obj = CloneObjectInLocalStack( rt , NULL , NULL ) ;
			if( obj == NULL )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CloneObjectInLocalStack out param failed[%d]" , nret )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_ALLOC;
			}
			else
			{
				TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS (rt)printf( "CloneObjectInLocalStack out param ok , " ); DebugPrintObject( rt , obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			}
		}
		else
		{
			struct ZlangObject		*parent_obj = NULL ;
			
			parent_obj = QueryGlobalObjectByObjectName( rt , func->out_param->parent_obj_name ) ;
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "QueryGlobalObjectByObjectName obj[%s] return " , func->out_param->parent_obj_name ); DebugPrintObject( rt , parent_obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			if( parent_obj == NULL )
			{
				SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED , "object '%s' not imported" , func->out_param->parent_obj_name )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_OBJECT_NOT_IMPORTED_OR_DECLARED;
			}
			
			obj = CloneObjectInLocalStack( rt , NULL , parent_obj ) ;
			if( obj == NULL )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CloneObjectInLocalStack out param failed[%d]" , nret )
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_ALLOC;
			}
			else
			{
				TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "CloneObjectInLocalStack out param ok , " ); DebugPrintObject( rt , obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			}
		}
	}
	new_local_objs_stack_frame->stack_out_params_top = new_local_objs_stack_frame->stack_local_var_top ;
	
	SetObjectsStackFullFuncName( new_local_objs_stack_frame , func->full_func_name );
	SetObjectsStackFullFuncName( new_tmp_objs_stack_frame , func->full_func_name );
	SetDefersStackFullFuncName( new_defers_stack_frame , func->full_func_name );
	
	in_param_index = 0 ;
	func_param = NULL ;
	while( ( func_param = TravelFunctionInputParameter( rt , func , func_param ) ) )
	{
		in = GetInputParameterInLocalObjectStack( rt , in_param_index+1 ) ;
		if( in == NULL )
			break;
		
		in_param_index++;
		
		if( STRCMP( func_param->parent_obj_name , == , ZLANG_OBJECT_vargs ) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "in param ZLANG_OBJECT_vargs found" )
			break;
		}
		else if( STRCMP( GetFunctionParameterParentObjectName(func_param) , == , ZLANG_OBJECT_object ) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "in param ZLANG_OBJECT_object found" )
		}
		else
		{
			if( func_param->obj_name )
			{
				nret = SetObjectName( rt , in , func_param->obj_name ) ;
				if( nret )
				{
					TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
					return nret;
				}
			}
		}
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "set local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , new_local_objs_stack_frame_curridx,new_local_objs_stack_frame->full_func_name , new_local_objs_stack_frame->stack_bottom,new_local_objs_stack_frame->stack_in_params_top,new_local_objs_stack_frame->stack_out_params_top,new_local_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "set tmp_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , new_tmp_objs_stack_frame_curridx,new_tmp_objs_stack_frame->full_func_name , new_tmp_objs_stack_frame->stack_bottom,new_tmp_objs_stack_frame->stack_in_params_top,new_tmp_objs_stack_frame->stack_out_params_top,new_tmp_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "set defers_stack_frame[%d][%s]-[%d][%d]" , new_defers_stack_frame_curridx,new_defers_stack_frame->full_func_name , new_defers_stack_frame->stack_bottom,new_defers_stack_frame->stack_top )
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretStatementSegment , is_in_uncatch[%d]" , interp_stat_ctx->is_in_uncatch )
	restore_in_obj = rt->in_obj ;
	restore_in_func = rt->in_func ;
	restore_token_datapage_header = rt->travel_token_datapage_header ;
	restore_token_dataunit = rt->travel_token_dataunit ;
	restore_token_info = rt->travel_token_info ;
	restore_token = rt->travel_token ;
	rt->in_obj = master_obj ;
	rt->in_func = func ;
	rt->travel_token_datapage_header = func->func_begin_token_datapage_header ;
	rt->travel_token_dataunit = func->func_begin_token_dataunit ;
	if( ! rt->checking_mode || IsTypeOf(rt,rt->in_obj,GetZObjectInRuntimeObjectsHeap(rt)) || IsTypeOf(rt,rt->in_obj,GetFunctionPtrObjectInRuntimeObjectsHeap(rt)) || IsTypeOf(rt,rt->in_obj,QueryGlobalObjectByObjectName(rt,ZLANG_OBJECT_zruntime)) )
		nret = InterpretStatementSegment( rt , interp_stat_ctx ) ;
	else
		nret = ZLANG_INFO_END_OF_STATEMENT_SEGMENT ;
	TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "InterpretStatementSegment return[%d] " , nret ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
	rt->in_obj = restore_in_obj ;
	rt->in_func = restore_in_func ;
	rt->travel_token_datapage_header = restore_token_datapage_header ;
	rt->travel_token_dataunit = restore_token_dataunit ;
	rt->travel_token_info = restore_token_info ;
	rt->travel_token = restore_token ;
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT && nret != ZLANG_INFO_RETURN && nret != ZLANG_INFO_EXIT )
	{
		DecreaseStackFrame( rt );
		old_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
		old_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
		old_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
		old_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
		old_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
		old_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_local_objs_stack_frame_curridx,old_local_objs_stack_frame->full_func_name , old_local_objs_stack_frame->stack_bottom,old_local_objs_stack_frame->stack_in_params_top,old_local_objs_stack_frame->stack_out_params_top,old_local_objs_stack_frame->stack_local_var_top )
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore tmp_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_tmp_objs_stack_frame_curridx,old_tmp_objs_stack_frame->full_func_name , old_tmp_objs_stack_frame->stack_bottom,old_tmp_objs_stack_frame->stack_in_params_top,old_tmp_objs_stack_frame->stack_out_params_top,old_tmp_objs_stack_frame->stack_local_var_top )
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore defers_stack_frame[%d][%s]-[%d][%d]" , old_defers_stack_frame_curridx,old_defers_stack_frame->full_func_name , old_defers_stack_frame->stack_bottom,old_defers_stack_frame->stack_top )
		
		if( HaveFatalException(rt) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveFatalException" )
			if( IsLocalObjectsStackFrameInTry(rt) )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_INFO_THROW;
			}
		}
		if( HaveErrorException(rt) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveErrorException , is_in_try[%d] is_in_uncatch[%d]" , IsLocalObjectsStackFrameInTry(rt) , interp_stat_ctx->is_in_uncatch )
			if( IsLocalObjectsStackFrameInTry(rt) && interp_stat_ctx->is_in_uncatch == FALSE )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_INFO_THROW;
			}
			
			CleanErrorException(rt);
		}
		
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	if( GetOutputParameterCountInLocalObjectStack( rt ) > 0 && STRCMP( func->out_param->parent_obj_name , != , ZLANG_OBJECT_void ) )
	{
		char		*obj_name = NULL ;

		DecreaseTmpObjectsStackFrame( rt );
		
		obj = GetOutputParameterInLocalObjectStack( rt , 1 ) ;
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "GetOutputParameterInLocalObjectStack " ); DebugPrintObject( rt , obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
		
		TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "refer from " ); DebugPrintObject( rt , obj ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
		(*result_obj) = ReferObjectInTmpStack( rt , obj ) ;
		if( (*result_obj) == NULL )
		{
			DecreaseLocalObjectsStackFrame( rt );
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return GET_RUNTIME_ERROR_NO(rt);
		}
		else
		{
			TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "refer ok " ); DebugPrintObject( rt , (*result_obj) ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
		}
		
		obj_name = GetObjectName( obj ) ;
		if( obj_name )
		{
			nret = SetObjectName( rt , (*result_obj) , obj_name ) ;
			if( nret )
			{
				DecreaseLocalObjectsStackFrame( rt );
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return GET_RUNTIME_ERROR_NO(rt);
			}
			else
			{
				TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "set object name ok " ); DebugPrintObject( rt , (*result_obj) ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
			}
		}

		DecreaseLocalObjectsStackFrame( rt );
		DecreaseDefersStackFrame( rt );
	}
	else
	{
		DecreaseStackFrame( rt );
		if( result_obj )
			(*result_obj) = NULL ;
	}
	
	old_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
	old_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
	old_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
	old_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
	old_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
	old_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_local_objs_stack_frame_curridx,old_local_objs_stack_frame->full_func_name , old_local_objs_stack_frame->stack_bottom,old_local_objs_stack_frame->stack_in_params_top,old_local_objs_stack_frame->stack_out_params_top,old_local_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore tmp_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_tmp_objs_stack_frame_curridx,old_tmp_objs_stack_frame->full_func_name , old_tmp_objs_stack_frame->stack_bottom,old_tmp_objs_stack_frame->stack_in_params_top,old_tmp_objs_stack_frame->stack_out_params_top,old_tmp_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore defers_stack_frame[%d][%s]-[%d][%d]" , old_defers_stack_frame_curridx,old_defers_stack_frame->full_func_name , old_defers_stack_frame->stack_bottom,old_defers_stack_frame->stack_top )
	
	TEST_RUNTIME_DEBUG( rt )
	{
		DebugStack( rt );
	}
	
	if( HaveFatalException(rt) )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveFatalException" )
		if( IsLocalObjectsStackFrameInTry(rt) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_INFO_THROW;
		}
	}
	if( HaveErrorException(rt) )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveErrorException , is_in_try[%d] is_in_uncatch[%d]" , IsLocalObjectsStackFrameInTry(rt) , interp_stat_ctx->is_in_uncatch )
		if( IsLocalObjectsStackFrameInTry(rt) && interp_stat_ctx->is_in_uncatch == FALSE )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_INFO_THROW;
		}
		
		// CleanErrorException(rt);
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	
	if( nret == ZLANG_INFO_EXIT )
		return nret;
	else
		return 0;
}

int InterpretExpression_InvokeConstractorFunction( struct ZlangRuntime *rt , struct ZlangInterpretStatementSegmentContext *interp_stat_seg_ctx , struct ZlangInterpretStatementContext *interp_stat_ctx , struct ZlangObject *obj )
{
	int		nret = 0 ;
	
	if( HadObjectConstracted(obj) == 1 )
		return 0;
	
	nret = InterpretExpression_InvokeFunction( rt , TOKEN_TYPE_MEMBER_OF , interp_stat_seg_ctx , interp_stat_ctx , obj , GetCloneObjectName(obj) , NULL ) ;
	if( nret )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "GetExpression_InvokeFunction failed[%d]" , nret )
		return nret;
	}
	else
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "GetExpression_InvokeFunction ok" )
	}
	
	SetObjectConstracted(obj);
	
	return 0;
}

int InterpretExpression_InvokeDefaultConstractorOrDestractorFunction( struct ZlangRuntime *rt , struct ZlangInterpretStatementSegmentContext *interp_stat_seg_ctx , struct ZlangInterpretStatementContext *interp_stat_ctx , unsigned char constractor_or_destractor , struct ZlangObject *obj )
{
	struct ZlangFunction		*func = NULL ;
	
	struct ZlangObjectsStackFrame	*old_local_objs_stack_frame = NULL ;
	int				old_local_objs_stack_frame_curridx ;
	struct ZlangObjectsStackFrame	*old_tmp_objs_stack_frame = NULL ;
	int				old_tmp_objs_stack_frame_curridx ;
	struct ZlangDefersStackFrame	*old_defers_stack_frame = NULL ;
	int				old_defers_stack_frame_curridx ;
	struct ZlangObjectsStackFrame	*new_local_objs_stack_frame = NULL ;
	int				new_local_objs_stack_frame_curridx ;
	struct ZlangObjectsStackFrame	*new_tmp_objs_stack_frame = NULL ;
	int				new_tmp_objs_stack_frame_curridx ;
	struct ZlangDefersStackFrame	*new_defers_stack_frame = NULL ;
	int				new_defers_stack_frame_curridx ;
	
	struct ZlangObject		*restore_in_obj = NULL ;
	struct ZlangFunction		*restore_in_func = NULL ;
	struct ZlangTokenDataPageHeader	*restore_token_datapage_header = NULL ;
	char				*restore_token_dataunit = NULL ;
	struct ZlangTokenDataUnitHeader	*restore_token_info = NULL ;
	char				*restore_token = NULL ;
	
	int				nret = 0 ;
	
	CHECK_ALART_STACK_DEPTH( rt->zlang_stack_bottom,&rt )

	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)

	if( constractor_or_destractor == IS_CONSTRACTOR )
	{
		if( HadObjectConstracted(obj) == 1 )
			return 0;
		
		func = GetFunctionsEntityConstractorFunction( GetObjectFunctionsEntity(obj) ) ;
		if( func == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return 0;
		}
	}
	else if( constractor_or_destractor == IS_DESTRACTOR )
	{
		if( HadObjectConstracted(obj) == 0 || HadObjectDestracted(obj) == 1 )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return 0;
		}
		
		func = GetFunctionsEntityDestractorFunction( GetObjectFunctionsEntity(obj) ) ;
		if( func == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return 0;
		}
	}
	else
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_PARAMETER , "parameter[%d] invalid" , constractor_or_destractor )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_INTERNAL;
	}
	
	old_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
	old_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
	old_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
	old_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
	old_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
	old_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "backup local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_local_objs_stack_frame_curridx,old_local_objs_stack_frame->full_func_name , old_local_objs_stack_frame->stack_bottom,old_local_objs_stack_frame->stack_in_params_top,old_local_objs_stack_frame->stack_out_params_top,old_local_objs_stack_frame->stack_local_var_top )
	
	IncreaseStackFrame( rt , func->full_func_name ) ;
	new_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
	new_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
	new_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
	new_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
	new_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
	new_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
	
	MarkInputParamtersTop( new_local_objs_stack_frame );
	MarkOutputParamtersTop( new_local_objs_stack_frame );
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "set local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , new_local_objs_stack_frame_curridx,new_local_objs_stack_frame->full_func_name , new_local_objs_stack_frame->stack_bottom,new_local_objs_stack_frame->stack_in_params_top,new_local_objs_stack_frame->stack_out_params_top,new_local_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "set tmp_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , new_tmp_objs_stack_frame_curridx,new_tmp_objs_stack_frame->full_func_name , new_tmp_objs_stack_frame->stack_bottom,new_tmp_objs_stack_frame->stack_in_params_top,new_tmp_objs_stack_frame->stack_out_params_top,new_tmp_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "set defers_stack_frame[%d][%s]-[%d][%d]" , new_defers_stack_frame_curridx,new_defers_stack_frame->full_func_name , new_defers_stack_frame->stack_bottom,new_defers_stack_frame->stack_top )
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretStatementSegment" )
	restore_in_obj = rt->in_obj ;
	restore_in_func = rt->in_func ;
	restore_token_datapage_header = rt->travel_token_datapage_header ;
	restore_token_dataunit = rt->travel_token_dataunit ;
	restore_token_info = rt->travel_token_info ;
	restore_token = rt->travel_token ;
	rt->in_obj = obj ;
	rt->in_func = func ;
	rt->travel_token_datapage_header = func->func_begin_token_datapage_header ;
	rt->travel_token_dataunit = func->func_begin_token_dataunit ;
	nret = InterpretStatementSegment( rt , interp_stat_ctx ) ;
	TEST_RUNTIME_DEBUG( rt ) { PRINT_TABS(rt) printf( "InterpretStatementSegment return[%d] " , nret ); PRINT_SOURCE_FILE_LINE PRINT_NEWLINE }
	rt->in_obj = restore_in_obj ;
	rt->in_func = restore_in_func ;
	rt->travel_token_datapage_header = restore_token_datapage_header ;
	rt->travel_token_dataunit = restore_token_dataunit ;
	rt->travel_token_info = restore_token_info ;
	rt->travel_token = restore_token ;
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT && nret != ZLANG_INFO_RETURN && nret != ZLANG_INFO_EXIT )
	{
		DecreaseStackFrame( rt );
		old_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
		old_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
		old_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
		old_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
		old_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
		old_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_local_objs_stack_frame_curridx,old_local_objs_stack_frame->full_func_name , old_local_objs_stack_frame->stack_bottom,old_local_objs_stack_frame->stack_in_params_top,old_local_objs_stack_frame->stack_out_params_top,old_local_objs_stack_frame->stack_local_var_top )
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore tmp_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_tmp_objs_stack_frame_curridx,old_tmp_objs_stack_frame->full_func_name , old_tmp_objs_stack_frame->stack_bottom,old_tmp_objs_stack_frame->stack_in_params_top,old_tmp_objs_stack_frame->stack_out_params_top,old_tmp_objs_stack_frame->stack_local_var_top )
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore defers_stack_frame[%d][%s]-[%d][%d]" , old_defers_stack_frame_curridx,old_defers_stack_frame->full_func_name , old_defers_stack_frame->stack_bottom,old_defers_stack_frame->stack_top )
		
		if( HaveFatalException(rt) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveFatalException" )
			if( IsLocalObjectsStackFrameInTry(rt) )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_INFO_THROW;
			}
		}
		if( HaveErrorException(rt) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveErrorException , is_in_try[%d] is_in_uncatch[%d]" , IsLocalObjectsStackFrameInTry(rt) , interp_stat_ctx->is_in_uncatch )
			if( IsLocalObjectsStackFrameInTry(rt) && interp_stat_ctx->is_in_uncatch == FALSE )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_INFO_THROW;
			}
			
			CleanErrorException(rt);
		}
		
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	DecreaseStackFrame( rt );
	
	old_local_objs_stack_frame = GetCurrentLocalObjectsStackFrame( rt ) ;
	old_local_objs_stack_frame_curridx = GetCurrentLocalObjectsStackFrameIndex( rt ) ;
	old_tmp_objs_stack_frame = GetCurrentTmpObjectsStackFrame( rt ) ;
	old_tmp_objs_stack_frame_curridx = GetCurrentTmpObjectsStackFrameIndex( rt ) ;
	old_defers_stack_frame = GetCurrentDefersStackFrame( rt ) ;
	old_defers_stack_frame_curridx = GetCurrentDefersStackFrameIndex( rt ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore local_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_local_objs_stack_frame_curridx,old_local_objs_stack_frame->full_func_name , old_local_objs_stack_frame->stack_bottom,old_local_objs_stack_frame->stack_in_params_top,old_local_objs_stack_frame->stack_out_params_top,old_local_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore tmp_objs_stack_frame[%d][%s]-[%d][%d][%d][%d]" , old_tmp_objs_stack_frame_curridx,old_tmp_objs_stack_frame->full_func_name , old_tmp_objs_stack_frame->stack_bottom,old_tmp_objs_stack_frame->stack_in_params_top,old_tmp_objs_stack_frame->stack_out_params_top,old_tmp_objs_stack_frame->stack_local_var_top )
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "restore defers_stack_frame[%d][%s]-[%d][%d]" , old_defers_stack_frame_curridx,old_defers_stack_frame->full_func_name , old_defers_stack_frame->stack_bottom,old_defers_stack_frame->stack_top )
	
	TEST_RUNTIME_DEBUG( rt )
	{
		DebugStack( rt );
	}
	
	if( constractor_or_destractor == IS_CONSTRACTOR )
	{
		SetObjectConstracted(obj);
	}
	else if( constractor_or_destractor == IS_DESTRACTOR )
	{
		SetObjectDestracted(obj);
	}
	
	if( HaveFatalException(rt) )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveFatalException" )
		if( IsLocalObjectsStackFrameInTry(rt) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_INFO_THROW;
		}
	}
	if( HaveErrorException(rt) )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "HaveErrorException , is_in_try[%d] is_in_uncatch[%d]" , IsLocalObjectsStackFrameInTry(rt) , interp_stat_ctx->is_in_uncatch )
		if( IsLocalObjectsStackFrameInTry(rt) && interp_stat_ctx->is_in_uncatch == FALSE )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_INFO_THROW;
		}
		
		CleanErrorException(rt);
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)

	if( nret == ZLANG_INFO_EXIT )
		return nret;
	else
		return 0;
}

